package com.one.pass.util;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.function.Function;

import static java.util.Optional.ofNullable;

//BeanUtils类提供了一系列操作Java对象反射的实用方法，包括获取和设置字段值、调用方法以及复制对象属性。

@Slf4j
public class BeanUtils {

    // 获取对象字段的值
    public static <T> T getValue(Object obj, String field) {
        Field f;
        try {
            f = obj.getClass().getDeclaredField(field);
            return getValue(obj, f);
        } catch (NoSuchFieldException ignored) {
            // 忽略异常
        }
        return (T) null;
    }

    // 获取指定类的对象字段的值
    public static <T> T getValue(Object obj, String field, Class<?> clazz) {
        Field f;
        try {
            f = clazz.getDeclaredField(field);
            return getValue(obj, f);
        } catch (NoSuchFieldException ignored) {
            // 忽略异常
        }
        return (T) null;
    }

    // 递归获取嵌套字段的值
    public static <T> T getFieldValue(Object obj, String key) {
        int index = key.indexOf(".");
        String name = key;
        if (index == 0) {
            name = key.substring(1);
        } else if (index > 0) {
            name = key.substring(0, index);
        }

        Class<?> cls = obj.getClass();
        while (cls != Object.class) {
            Field field = null;
            try {
                field = cls.getDeclaredField(name);
            } catch (NoSuchFieldException e) {
                // 忽略异常
            }

            if (field == null) {
                cls = cls.getSuperclass();
                continue;
            }
            field.setAccessible(true);
            Object valueObject = null;
            try {
                valueObject = field.get(obj);
            } catch (IllegalAccessException e) {
                // 忽略异常
            }
            if (valueObject != null) {
                if (index <= 0) {
                    return (T) valueObject;
                }
                return getFieldValue(valueObject, key.substring(index + 1));
            } else {
                return null;
            }
        }
        return null;
    }

    // 调用静态方法
    public static Object invoke(Class<?> cls, String method, Class<?>[] paramsClass, Object[] objects) {
        Method me;
        try {
            me = cls.getMethod(method, paramsClass);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
            return null;
        }
        try {
            return me.invoke(null, objects);
        } catch (IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }

    // 调用实例方法
    @SneakyThrows
    public static Object invoke(Object service, String method, Class<?> paramClass, Object params) {
        Method method1 = service.getClass().getMethod(method, paramClass);
        return method1.invoke(service, params);
    }

    // 获取字段的值
    public static <T> T getValue(Object obj, Field field) {
        try {
            field.setAccessible(true);
            return (T) field.get(obj);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    // 设置字段的值
    public static void setValue(Object obj, String field, Object value) {
        Field f;
        try {
            f = obj.getClass().getDeclaredField(field);
            f.setAccessible(true);
            f.set(obj, value);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    // 设置字段的值
    public static void setValue(Object obj, Field field, Object value) {
        field.setAccessible(true);
        try {
            field.set(obj, value);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    // 复制对象属性
    public static <T> T copy(Object source, Class<T> clazz) {
        try {
            T t = clazz.newInstance();
            org.springframework.beans.BeanUtils.copyProperties(source, t);
            return t;
        } catch (InstantiationException | IllegalAccessException ignored) {
            log.info(ignored.getMessage(), ignored);
        }
        return null;
    }

    // 复制非空属性
    public static void copyNullAToB(Object source, Object target) {
        Arrays.stream(source.getClass().getDeclaredFields())
                .forEach(field -> {
                    Object result = getValue(source, field);
                    if (result != null) {
                        setValue(target, field.getName(), result);
                    }
                });
    }

    // 提供复制对象属性的Function
    public static <T, R> Function<T, R> copy(Class<R> clazz) {
        return t -> copy(t, clazz);
    }
}
